﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Text;
using System.IO;
using SdmxMl.GenericMetadata;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Manager;
using DW.RtfWriter;
using System.Diagnostics;

namespace SdmxMl.Report
{
    public class WorldHtmlAttribute
    {
        private AttributeValueSetType attribValueSet;
        private ReportStructureType reportStructure;
        private SmManager sm;

        private bool includeConceptNote;
        private bool includeConceptId;

        private RtfDocument doc;
        private FontDescriptor times;
        private FontDescriptor arial;
        private FontDescriptor courier;
        private ColorDescriptor red;
        private ColorDescriptor blue;

        /// Don't instantiate RtfTable, RtfParagraph, and RtfImage objects by using
        /// ``new'' keyword. Instead, use add* method in objects derived from 
        /// RtfBlockList class. (See Demos.)
        private RtfParagraph par;
        private MetadataStructureDefinitionType _msd;

        public WorldHtmlAttribute(MetadataStructureDefinitionType msd)
        {
            _msd = msd;
            sm = ReferenceManager.GetSmContainerImage();
            List<Lcid> listLcid = FillLcidList();
            doc = new RtfDocument(PaperSize.A4, PaperOrientation.Portrait, listLcid[LangSupport.CurLangIndex]);

            /// Create fonts and colors for later use
            arial = doc.createFont("Arial Narrow");
            times = doc.createFont("Times New Roman");
            courier = doc.createFont("Courier New");
            red = doc.createColor(new Color("ff0000"));
            blue = doc.createColor(new Color(0, 0, 255));

        }

        private List<Lcid> FillLcidList()
        {
            List<Lcid> listLcid = new List<Lcid>();
            foreach (string lg in LangSupport.SupportedLanguages)
            {
                switch (lg)
                {
                    case "de": listLcid.Add(Lcid.German); break;
                    case "fr": listLcid.Add(Lcid.French); break;
                    case "it": listLcid.Add(Lcid.Italian); break;
                    default: listLcid.Add(Lcid.English); break;
                }
            }
            return listLcid;
        }

        private void ReportAttributeList(int level, ReportedAttributeTypeList rptList)
        {
            string conceptNote = string.Empty;
            foreach (ReportedAttributeType r in rptList)
            {
                string conceptName = GetConceptName(r, ref conceptNote);

                par = doc.addParagraph();
                par.DefaultCharFormat.Font = arial;
                if (level == 0)
                    par.DefaultCharFormat.BgColor = doc.createColor(new Color(122, 0, 200));
                par.DefaultCharFormat.FontSize = 12 - 2 * level;
                par.Margins[Direction.Left] = 10 * level;

                par.Text = conceptName;

                if (conceptNote.Length > 0)
                {
                    par = doc.addParagraph();
                    par.DefaultCharFormat.Font = arial;
                    par.DefaultCharFormat.FontSize = 8;
                    par.Margins[Direction.Left] = 10 * level;
                    par.Text = conceptNote + Environment.NewLine;
                }

                if (r.Value.IsEmpty == false)
                {
                    par = doc.addParagraph();
                    par.Margins[Direction.Left] = 10 * level;
                    par.DefaultCharFormat.Font = courier;
                    par.DefaultCharFormat.FontSize = 9;
                    par.DefaultCharFormat.FgColor = blue;
                    // Here PRA
                    if (_msd == null)
                        par.Text = r.Value.ToString();
                    else
                        par.Text = GenerateTextFromAttribute(r);
                }

                if (r.ReportedAttributeList.Count > 0)
                    ReportAttributeList(level + 1, r.ReportedAttributeList);
                if (level == 0)
                par = doc.addParagraph();
            }

        }

        private string GenerateTextFromAttribute(ReportedAttributeType r)
        {
            string val = string.Empty;

            if (r != null && _msd != null)
            {
                 val = r.Value.ToString();
                 MetadataAttributeType meta = reportStructure.MetadataAttributeList.GetAttributeReferingConcept(r.ConceptID);
                 if (meta != null)
                 {
                     // value is code of a codelist ?
                     if (meta.RepresentationInfo.IsFilled)
                     {
                         // TODO case codelist in concept
                         CodeListType clt = sm.GetArtefact(SdmxArtefactType.CodeLists, meta.RepresentationInfo) as CodeListType;
                         if (clt != null)
                         {
                             if (meta.MetaOccurence.IsMultiCodes)
                             {
                                 string[] arr = val.Split(';');
                                 StringBuilder sb = new StringBuilder();

                                 for (int i = 0; i < arr.Length; ++i)
                                 {
                                    ISdmxHierarchyListItem item = clt.CodeList.LocateItem(arr[i]);
                                    if (item != null)
                                    {
                                        sb.Append(item.Id).Append(" - ").Append(item.Name.ToString());
                                        if (i < arr.Length - 1)
                                            sb.Append(Environment.NewLine);
                                    }
                                 }
                                 val = sb.ToString();
                             }
                             else
                             {
                             ISdmxHierarchyListItem item = clt.CodeList.LocateItem(val);
                             if (item != null)
                                 val = val + " - " + item.Name.ToString();
                             }
                         }
                     }
                     else if (meta.TextFormat.TextType == TextTypeType.URI)
                     {
                        string urn = val;
                        ArtefactRefTyped art = null;
                        if (urn.StartsWith(UrnManager.UrnBase))
                        {
                            UrnParser p = new UrnParser(urn);
                            if (p.IsSupported)
                            {
                                art = new ArtefactRefTyped(p.ArType, p.ArtefactId, p.AgencyId, p.Version);

                                if (p.SubType == "Concept")
                                {
                                    ConceptSchemeType cst = sm.GetArtefact(SdmxArtefactType.Concepts, art, true) as ConceptSchemeType;
                                    if (cst != null)
                                    {
                                        ISdmxHierarchyListItem item = cst.ConceptList.LocateItem(p.SubTypeId);
                                        if (item != null)
                                            val = p.SubTypeId + " - " + item.Name.ToString();
                                    }
                                }
                                else if (p.ArType == SdmxArtefactType.CodeLists)
                                {
                                    CodeListType clt = sm.GetArtefact(SdmxArtefactType.CodeLists, art, true) as CodeListType;
                                    if (clt != null)
                                    {
                                        StringBuilder sb = new StringBuilder();
                                        foreach (CodeType c in clt.CodeList)
                                        {
                                            sb.Append(c.Id).Append(" - ").Append(c.Name.ToString());
                                            sb.Append(Environment.NewLine);
                                        }
                                        val = sb.ToString();

                                    }
                                }
                            }
                        }
                     
                    }
                 }
            }

            return val;
        }

        public string MakeRtfReport(AttributeValueSetType attribValueSet, ReportStructureType rep, bool includeConceptNote, bool incConceptId)
        {

            this.reportStructure = rep;
            this.attribValueSet = attribValueSet;
            this.includeConceptNote = includeConceptNote;
            this.includeConceptId = incConceptId;
            string conceptNote = string.Empty;

            try
            {
                // Header & Footer
                par = doc.Footer.addParagraph();
                par.Text = "SMS Report (www.sdmx.ch)  Page: /      Date:   Time:";
                par.Alignment = Align.Center;
                par.DefaultCharFormat.FontSize = 10;
                /// Insert control words, including page number, total pages, date and
                /// time, into the header and/or the footer. 
                par.addControlWord(17, RtfFieldControlWord.FieldType.Page);
                par.addControlWord(18, RtfFieldControlWord.FieldType.NumPages);
                par.addControlWord(31, RtfFieldControlWord.FieldType.Date);
                par.addControlWord(37, RtfFieldControlWord.FieldType.Time);

                /// Here we also add some text in header.
                par = doc.Header.addParagraph();
                par.Text = attribValueSet.ParentMetadataSet.Name.ToString() + "     " + attribValueSet.TargetValuesTypeList[0].Value;

                ReportAttributeList(0, attribValueSet.ReportedAttributeList);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Report Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

            }


            return doc.render();
        }

        public void CallRtfEditor()
        {
            doc.save("Demo.rtf");


            /// ==========================================================================
            /// Open the RTF file we just saved
            /// ==========================================================================
            Process p = new Process();
            p.StartInfo.FileName = "Demo.rtf";
            p.Start();

        }

        public string GetHeader()
        {
            StringBuilder strBody = new StringBuilder(1024);

            strBody.Append("<html " +
                    "xmlns:o='urn:schemas-microsoft-com:office:office' " +
                    "xmlns:w='urn:schemas-microsoft-com:office:word'" +
                    "xmlns='http://www.w3.org/TR/REC-html40'>" +
                    "<head><title>Time</title>");

            // The setting specifies document's view after it is downloaded as Print
            // instead of the default Web Layout

            strBody.Append("<!--[if gte mso 9]>" +
                                     "<xml>" +
                                     "<w:WordDocument>" +
                                     "<w:View>Print</w:View>" +
                                     "<w:Zoom>90</w:Zoom>" +
                                     "<w:DoNotOptimizeForBrowser/>" +
                                     "</w:WordDocument>" +
                                     "</xml>" +
                                     "<![endif]-->");

            strBody.Append("<style>" +
                                    "<!-- /* Style Definitions */" +
                                    "@page Section1" +
                                    "   {size:8.5in 11.0in; " +
                                    "   margin:1.0in 1.25in 1.0in 1.25in ; " +
                                    "   mso-header-margin:.5in; " +
                                    "   mso-footer-margin:.5in; mso-paper-source:0;}" +
                                    " div.Section1" +
                                    "   {page:Section1;}" +
                                    "-->" +
                                   "</style></head>");

            strBody.Append("<body lang=EN-US style='tab-interval:.5in'>" +
                                    "<div class=Section1>" +
                                    "<h1 align=center style='text-align:center;background:#FFCC99'><span lang=EN-US " +
                                    "style='font-family:Comic Sans MS;mso-ansi-language:EN-US'>SMS Report (www.sdmx.ch)<o:p></o:p></h1>" +
                                    "<p align=center><I>" +
                                    DateTime.Now.ToString("yyyy.MM.dd") + " at: " + DateTime.Now.ToShortTimeString() + "</I></p>");

            strBody.Append("<h1 align=center style='text-align:center;background:#E6E6E6'><span lang=EN-US " +
                "style='font-size:14.0pt;font-family:Comic Sans MS;mso-ansi-language:EN-US'>");
            strBody.Append(attribValueSet.ParentMetadataSet.Name.ToString()).Append(" &#8211; ");
            strBody.Append(attribValueSet.TargetValuesTypeList[0].Value).Append("<o:p></o:p></span></h1>");

            return strBody.ToString();
        }

        private string GetSpaces(int nb)
        {
            StringBuilder sb = new StringBuilder(29);
            for (int i = 0; i < nb; i++)
                sb.Append("&nbsp;");
            return sb.ToString();
        }

        private string GetLink(string link, string text)
        {
            return "<a href=\"" + link + "\">" + text + "</a>";
        }

        private string GetSimpleText2(string text)
        {
            return "<p class=MsoNormal style='margin-left:36.0pt;text-indent:36.0pt'><span" +
                "lang=EN-GB style='mso-ansi-language:EN-GB'>" + text + "<o:p></o:p></span></p>";

        }

        private string GetSimpleText(string text)
        {
       //      return "<span lang=EN-GB style='mso-ansi-language:EN-GB'>" + text + "</span><br>";

           return "<p class=MsoNormal style='margin-top:0.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm'><span lang=EN-GB style='font-family:Comic Sans MS;mso-ansi-language:EN-GB'>" +
                text + "</span><span lang=EN-US style='font-family:Comic Sans MS;mso-ansi-language:EN-US'><o:p></o:p></span></p>";

        }
        private string GetFooter()
        {
            return "</div></body></html>";
        }

        private string GetBlocTitle(string title, string comment)
        {
            StringBuilder sb = new StringBuilder(1024);
            sb.Append("<table class=MsoTableGrid border=1 cellspacing=3 cellpadding=2 style='background:#FFCC99;border-collapse:collapse;mso-yfti-tbllook:480;mso-padding-alt:0cm 5.4pt 0cm 5.4pt'>");
            sb.Append("<tr><td> <p class=MsoNormal><span lang=EN-GB style='font-family:Arial;mso-ansi-language: EN-GB'>");
            sb.Append(title);
            sb.Append("</span></p> </td> </tr>");
        
        if (comment != null && comment.Length > 0)
        {
            sb.Append("<tr style='mso-yfti-irow:1;mso-yfti-lastrow:yes'>  <td style='padding:0cm 5.4pt 0cm 5.4pt'>");
            sb.Append("<p class=MsoNormal style='mso-margin-top-alt:auto;mso-margin-bottom-alt:auto'>");
            sb.Append("<span lang=EN-GB style='font-size:8.0pt;font-family:Tahoma;mso-ansi-language:EN-GB'>");
            sb.Append(comment);
            sb.Append("<span style='mso-spacerun:yes'></span><o:p></o:p></span></p></td></tr>");
        }

        sb.Append("</table><p class=MsoNormal style='margin-top:3.0pt;margin-right:0cm;margin-bottom:0.0pt;margin-left:0cm'><span lang=EN-GB style='font-size:2.0pt;font-family:Tahoma;mso-ansi-language:EN-GB'>&nbsp;</span></p>");

        return sb.ToString(); ;
        }

        private string GetFileTitle(string title)
        {
            return "<table class=MsoTableGrid border=1 cellspacing=0 cellpadding=0 " +
        "style='margin-left:9.15pt;background:#FFFFCC;border-collapse:collapse;" +
        "border:none;mso-border-alt:solid windowtext .5pt;mso-yfti-tbllook:480;" +
        "mso-padding-alt:0cm 5.4pt 0cm 5.4pt;mso-border-insideh:.5pt solid windowtext;" +
        "mso-border-insidev:.5pt solid windowtext'>" +
        "<tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes'>" +
        "<td  valign=center style='border:solid windowtext 1.0pt;" +
        "mso-border-alt:solid windowtext .5pt;padding:0cm 5.4pt 0cm 5.4pt'> " +
           "<span lang=EN-GB style='font-family:Arial;mso-ansi-language: EN-GB'>" +
           title +
           "&nbsp;<o:p></o:p></span></td></tr>" +
           "</table><p class=MsoNormal style='margin-top:3.0pt;margin-right:0cm;margin-bottom:0.0pt;margin-left:0cm'><span lang=EN-GB style='font-size:2.0pt;font-family:Tahoma;mso-ansi-language:EN-GB'>&nbsp;</span></p>";
        }

        public void WriteReport(string report, string path)
        {
            using (StreamWriter sw = new StreamWriter(path, false, Encoding.Default))
            {
                sw.Write(report);
                sw.Close();
            }
        }
        /*
        public string MakeReport(AttributeValueSetType attribValueSet, ReportStructureType rep, bool includeConceptNote)
        {
            this.reportStructure = rep;
            this.attribValueSet = attribValueSet;
            this.includeConceptNote = includeConceptNote;
            string conceptNote = string.Empty;

       //TODO codelist text     MetadataAttributeType meta = reportStructure.MetadataAttributeList.GetAttributeReferingConcept(_reportedAttribute.ConceptID);

            StringBuilder sb = new StringBuilder(1024);
            sb.Append(GetHeader());

            foreach (ReportedAttributeType r in attribValueSet.ReportedAttributeList)
            {
                string conceptName = GetConceptName(r, ref conceptNote);
                sb.Append(GetBlocTitle(conceptName, conceptNote));
                if (conceptNote.Length > 0)
                    sb.Append("");
                
                if (r.Value.IsEmpty == false)
                    sb.Append(GetSimpleText(r.Value.ToString()));
                if (r.ReportedAttributeList.Count > 0)
                {
                    foreach (ReportedAttributeType rChild in r.ReportedAttributeList)
                    {
                        sb.Append(GetFileTitle(GetConceptName(rChild, ref conceptNote)));
                        if (rChild.Value.IsEmpty == false)
                            sb.Append(GetSimpleText(rChild.Value.ToString()));
                    }
                }
            }
            sb.Append(GetFooter());
            return sb.ToString();

        }
        */

        private string GetConceptName(ReportedAttributeType r, ref string conceptNote)
        {
            conceptNote = string.Empty;
            string name = r.ConceptID;
            if (reportStructure != null)
            {
                MetadataAttributeType meta =
                    reportStructure.MetadataAttributeList.GetAttributeReferingConcept(r.ConceptID);
                if (meta != null)
                {
                    ConceptSchemeType cst = ReferenceManager.LocateConceptScheme(meta.ConceptSchemeInfo);
                    ConceptType c = ReferenceManager.LocateConcept(cst, r.ConceptID);
                    if (c != null)
                    {
                        string conceptName = c.Name.ToString();
                        if (conceptName.Length > 0)
                        {
                            if (includeConceptId)
                                name += " - " + conceptName;
                            else
                                name = conceptName;
                        }
                        if (includeConceptNote)
                        {
                            conceptNote = c.AnnotationList.GetTextOfAnnotationType("CONTEXT");
                            if (string.IsNullOrEmpty(conceptNote))
                                if (c.Description.ToString() != MultiLang.UndefinedText)
                                    conceptNote = c.Description.ToString();
                        }
                    }
                }
            }
            return name;
        }
    }
}
   

